import serial
import time
import os
import sys
import random
import re
import subprocess
import threading


# 定义常量
DEBUG_PORT = "COM4"
AT_PORT = "COM39"
BAUDRATE = 115200
# 定义变量
at_serial = None
debug_serial = None
# 记录运行次数
runTimes = 0
# log文件
DEBUG_LOG = ""
ADB_LOG = ""
AT_LOG = ""


# 创建日志文件
def createLogFile():
    global DEBUG_LOG, ADB_LOG, AT_LOG
    timestamp = time.strftime("%Y-%m-%d_%H_%M_%S", time.localtime())
    DEBUG_LOG = f"DEBUG_LOG_{timestamp}.log"
    ADB_LOG = f"ADB_LOG_{timestamp}.log"
    AT_LOG = f"AT_LOG_{timestamp}.log"

    with open(DEBUG_LOG, "w", encoding="utf-8") as file:
        file.write("DEBUG 日志开始记录...\n")

    with open(ADB_LOG, "w", encoding="utf-8") as file:
        file.write("ADB 日志开始记录...\n")

    with open(AT_LOG, "w", encoding="utf-8") as file:
        file.write("AT 日志开始记录...\n")


# 写日志
def write_log(log, logFile):
    with open(logFile, "a", encoding="utf-8") as file_object:
        file_object.write(
            str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
            + "\r\n"
            + log
            + "\r\n"
        )
        now_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        print("[" + now_time + "]" + " " + log)


# Send at instruction
def at_write(command, timeout, at_port_opened, at_result, RDY=0, CPIN=0):
    at_command = command.encode("UTF-8")
    at_port_opened.write(at_command)


# 读取at口返回
def at_read(serial_port, logFile=""):
    rec_str = ""
    while True:
        time.sleep(1)
        lenth = serial_port.inWaiting()
        if lenth > 0:
            rec_str = serial_port.read(size=lenth)
            try:
                rec_str = re.sub("\\x1b.*?m", "", rec_str.decode("UTF-8"), 0, re.I)
                if logFile != "":
                    with open(logFile, "a") as file_object:
                        rec_str = (
                            str(time.time())
                            + ":"
                            + str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
                            + "\r\n"
                            + rec_str
                        )
                        file_object.write(
                            str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
                            + "\r\n"
                            + rec_str
                            + "\r\n"
                        )
                return rec_str
            except:
                return ""
        else:
            break
    return rec_str


# 登录设备
def loginDevice():
    global DEBUG_LOG
    # 确认登录失败的条件，或者，不可能失败
    while True:
        #   print("等待登录... ... ")
        write_log("等待登录... ... ", DEBUG_LOG)
        time.sleep(3)
        at_write("\r\n", 3, debug_serial, "OK")
        result = at_read(debug_serial)

        with open(DEBUG_LOG, "a") as file_object:
            file_object.write(result)

        if "login:" in result:
            at_write("root\r\n", 3, debug_serial, "OK")
            #    print("账号输入成功")
            write_log("账号输入成功", DEBUG_LOG)
            time.sleep(2)
            at_write("oelinux123\r\n", 3, debug_serial, "OK")
            #    print("密码输入成功")
            write_log("密码输入成功", DEBUG_LOG)
        elif "~ #" in result:
            #    print("登录成功")
            write_log("登录成功", DEBUG_LOG)
            break
        else:
            continue


# 检查debug口通信状态
def check_port_status():
    global debug_serial
    if debug_serial == None:
        try:
            debug_serial = serial.Serial(DEBUG_PORT, BAUDRATE)
        except:
            print("端口连接失败，请检查端口")
            sys.exit()


# 写入运行次数到日志
def writeRuntimesToLog():
    global runTimes
    with open(DEBUG_LOG, "a+") as file_object:
        file_object.write(
            "\r\n{} runtimes: {} {}\r\n".format("<" * 20, runTimes, ">" * 20)
        )
    #  print("\r\n{} runtimes: {} {}\r\n".format("<"*20,runTimes,">"*20))
    with open(AT_LOG, "a+") as file_object:
        file_object.write(
            "\r\n{} runtimes: {} {}\r\n".format("<" * 20, runTimes, ">" * 20)
        )
    #  print("\r\n{} runtimes: {} {}\r\n".format("<"*20,runTimes,">"*20))
    with open(ADB_LOG, "a+") as file_object:
        file_object.write(
            "\r\n{} runtimes: {} {}\r\n".format("<" * 20, runTimes, ">" * 20)
        )
    print("\r\n{} runtimes: {} {}\r\n".format("<" * 20, runTimes, ">" * 20))
    runTimes += 1


# 发送AT指令
def send_at_command(command):
    # 打开串口
    ser = serial.Serial(AT_PORT, BAUDRATE)
    ser.write((command + "\r\n").encode())
    ser.write(("\r\n").encode())
    time.sleep(6)
    response = ser.read_all().decode()
    ser.close()
    # write_log(f"at指令{command}执行结果:{response}",AT_LOG)
    with open(AT_LOG, "a", encoding="utf-8") as file_object:
        file_object.write(
            str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
            + "\r\n"
            + response
            + "\r\n"
        )
    return response


# 发送adb命令
def send_adb_command(command):
    try:
        # 使用 subprocess 模块执行 adb shell 命令
        result = subprocess.run(
            ["adb", "shell", command], capture_output=True, text=True
        )
        with open(ADB_LOG, "a", encoding="utf-8") as file_object:
            file_object.write(
                str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
                + "\r\n"
                + result.stdout
                + "\r\n"
            )
        # 返回命令的输出结果
        return result.stdout
    except Exception as e:
        return str(e)


# 查看APN
def check_APN():
    write_log("开始查看APN", AT_LOG)
    result = send_at_command("AT+CGDCONT?;+CGACT?")
    return result


# 删除APN
def remove_APN(apn_id):
    write_log(f"开始删除APN{apn_id}", AT_LOG)
    send_at_command("AT+CGDCONT={}".format(apn_id))


# 写入运行次数到日志
def writeRuntimesToLog():
    global runTimes
    with open(DEBUG_LOG, "a+") as file_object:
        file_object.write(
            "\r\n{} runtimes: {} {}\r\n".format("<" * 20, runTimes, ">" * 20)
        )
    print("\r\n{} runtimes: {} {}\r\n".format("<" * 20, runTimes, ">" * 20))
    runTimes += 1


# 进入测试接口
def intoTestInterface_testsdk(debug_serial, logFile):
    at_write("cd /data\r\n./test_sdk_ms_api\r\n", 3, debug_serial, "OK")
    write_log("进入测试接口", logFile)
    time.sleep(3)
    at_write("0\n", 3, debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(3)
    at_write("0\n", 3, debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(3)
    result = at_read(debug_serial, logFile)


# 退出测试接口
def exit_testsdk(debug_serial, logFile):
    at_write("-1\n-1\n", 3, debug_serial, "OK")
    result = at_read(debug_serial, logFile)


# 返回测试接口
def back_testsdk(debug_serial, logFile):
    at_write("-1\n", 3, debug_serial, "OK")
    result = at_read(debug_serial, logFile)


# 创建测试APN
def set_apn_testsdk(testapn, testapn_name, simid):
    write_log(f"开始创建测试APN{testapn}，名称{testapn_name}", DEBUG_LOG)
    time.sleep(3)
    at_write("10\n", 3, debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(3)
    at_write("{}\n".format(testapn), 3, debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)
    at_write("3\n", 3, debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)
    at_write("3\n", 3, debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)
    at_write("{}\n".format(testapn_name), 3, debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)
    at_write("\n", 3, debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)
    at_write("\n", 3, debug_serial, "OK")
    time.sleep(3)
    at_write("{}\n".format(simid), 3, debug_serial, "OK")
    time.sleep(3)
    result = at_read(debug_serial, DEBUG_LOG)
    if "Successful" in result:
        write_log(f"测试APN{testapn}创建成功", DEBUG_LOG)
    else:
        write_log(f"测试APN{testapn}创建失败", DEBUG_LOG)
    at_write("\n", 3, debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)


# 创建并设置datacall
def set_datacall1_testsdk(datacall_id, datacall_name, testapn, simid):
    write_log(
        f"开始设置datacall{datacall_id}，名称{datacall_name}设置的APN为{testapn}路",
        DEBUG_LOG,
    )
    time.sleep(1)
    at_write("1\n", 3, debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(3)
    at_write("{}\n".format(datacall_id), 3, debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(1)
    at_write("{}\n".format(datacall_name), 3, debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(3)
    at_write("1\n", 3, debug_serial, "OK")
    time.sleep(3)
    result1 = at_read(debug_serial, DEBUG_LOG)
    if "Successful" in result1:
        write_log(f"datacall{datacall_id}创建成功", DEBUG_LOG)
    else:
        write_log(f"datacall{datacall_id}创建失败", DEBUG_LOG)

    at_write("\n", 3, debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)
    at_write("2\n", 3, debug_serial, "OK")
    time.sleep(3)
    at_write("{}\n".format(datacall_id), 3, debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(3)
    at_write("{}\n".format(testapn), 3, debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(1)
    at_write("1\n", 3, debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(3)
    at_write("0\n", 3, debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)
    at_write("\n", 3, debug_serial, "OK")
    time.sleep(3)
    at_write("{}\n".format(simid), 3, debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)
    at_write("y\n", 3, debug_serial, "OK")
    time.sleep(3)
    result2 = at_read(debug_serial, DEBUG_LOG)
    if "Successful" in result2:
        write_log(f"datacall{datacall_id}设置APN{testapn}成功", DEBUG_LOG)
    else:
        write_log(f"datacall{datacall_id}设置APN{testapn}失败", DEBUG_LOG)
    at_write("\n", 3, debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)


# 启动datacall
def start_datacall_testsdk(datacall_id):
    write_log(f"开始拨号datacall：{datacall_id}", DEBUG_LOG)
    at_write("4\n", 3, debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)
    at_write("{}\n".format(datacall_id), 3, debug_serial, "OK")
    time.sleep(3)
    result = at_read(debug_serial, DEBUG_LOG)
    if "Successful" in result:
        write_log(f"datacall{datacall_id}拨号成功", DEBUG_LOG)
    else:
        write_log(f"datacall{datacall_id}拨号失败", DEBUG_LOG)
    at_write("8\n", 3, debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)
    at_write("{}\n".format(datacall_id), 3, debug_serial, "OK")
    time.sleep(5)
    at_read(debug_serial, DEBUG_LOG)
    at_write("\n", 3, debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)


# 删除datacall
def remove_datacall_testsdk(datacall_id):
    time.sleep(3)
    write_log(f"开始停止并删除datacall：{datacall_id}", DEBUG_LOG)
    at_write("5\n", 3, debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)
    at_write("{}\n".format(datacall_id), 3, debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)
    at_write("6\n", 3, debug_serial, "OK")
    time.sleep(3)
    at_read(debug_serial, DEBUG_LOG)
    at_write("{}\n".format(datacall_id), 3, debug_serial, "OK")
    time.sleep(3)
    result = at_read(debug_serial, DEBUG_LOG)
    if "Successful" in result:
        write_log(f"datacall{datacall_id}删除成功", DEBUG_LOG)
    else:
        write_log(f"datacall{datacall_id}删除失败", DEBUG_LOG)
    at_write("\n", 3, debug_serial, "OK")
    time.sleep(3)


# 通过ADB命令ping测试
def ping_testsdk(test_url):
    write_log("通过ADB调试开始ping网测试", ADB_LOG)
    result = send_adb_command("ping -I rmnet_data0 -c 10 {}".format(test_url))
    # write_log(f"ping测试结果:\n{result}", ADB_LOG)
    if " 100%" in result:
        write_log("data0,丢包率为100%", ADB_LOG)
    else:
        write_log("data0,丢包率不为100%,测试通过", ADB_LOG)
    result = send_adb_command("ping -I rmnet_data1 -c 10 {}".format(test_url))
    # write_log(f"ping测试结果:\n{result}", ADB_LOG)
    if " 100%" in result:
        write_log("data1,丢包率为100%", ADB_LOG)
    else:
        write_log("data1,丢包率不为100%,测试通过", ADB_LOG)
    result = send_adb_command("ping -I rmnet_data2 -c 10 {}".format(test_url))
    # # write_log(f"ping测试结果:\n{result}", ADB_LOG)
    # if " 100%" in result:
    #     write_log("data1,丢包率为100%", ADB_LOG)
    # else:
    #     write_log("data1,丢包率不为100%,测试通过", ADB_LOG)


# 开始查看网卡信息
def check_network_info():
    write_log("开始查看网卡信息", AT_LOG)
    result = send_adb_command("ifconfig")
    return result


def extract_apn_ids(at_response):
    apn_ids = []
    # 按行拆分 AT 响应
    lines = at_response.splitlines()

    for line in lines:
        # 检查行是否以 "+CGDCONT" 开头
        if line.startswith("+CGDCONT"):
            # 按逗号分割并提取第一个字段（包含 ID）
            parts = line.split(",")
            if len(parts) > 0:
                # 提取出 "+CGDCONT: ID" 中的 ID 部分
                apn_id = parts[0].split(":")[1].strip()
                apn_ids.append(apn_id)

    write_log(f"APN ID 列表：{apn_ids}", AT_LOG)
    return apn_ids


def check_apn_in_list(apn_ids, target_ids):
    # 遍历每个目标ID，检查是否在apn_ids列表中
    for target_id in target_ids:
        if target_id in apn_ids:
            # print(f"APN ID {target_id} 存在于结果中")
            write_log(f"APN ID {target_id} 存在于结果中", AT_LOG)
        else:
            # print(f"APN ID {target_id} 不存在于结果中")
            write_log(f"APN ID {target_id} 不存在于结果中", AT_LOG)


# 匹配网卡信息
def extract_network_info(network_info, target_network_cards):
    # 定义正则表达式模式，匹配网卡信息
    pattern = (
        r"(\w+)\s+Link encap:\w+\s+HWaddr\s+([\w:.-]+)\s*"
        r"(?:inet addr:(\d+\.\d+\.\d+\.\d+))?\s*"
        r"(?:Bcast:(\d+\.\d+\.\d+\.\d+))?\s*"
        r"(?:Mask:(\d+\.\d+\.\d+\.\d+))?"
    )

    # 使用正则表达式查找匹配项
    matches = re.findall(pattern, network_info)
    network_cards = []

    # 提取匹配到的网卡信息并打印
    for match in matches:
        interface, mac_addr, inet_addr, bcast, mask = match
        network_cards.append(interface)
        # print(f"网卡: {interface}")
        write_log(f"网卡: {interface}", ADB_LOG)
        # print(f"MAC地址: {mac_addr}")
        write_log(f"MAC地址: {mac_addr}", ADB_LOG)
        # print(f"IP地址: {inet_addr if inet_addr else 'N/A'}")
        write_log(f"IP地址: {inet_addr if inet_addr else 'N/A'}", ADB_LOG)
        # print(f"广播地址: {bcast if bcast else 'N/A'}")
        write_log(f"广播地址: {bcast if bcast else 'N/A'}", ADB_LOG)
        # print(f"子网掩码: {mask if mask else 'N/A'}")
        write_log(f"子网掩码: {mask if mask else 'N/A'}", ADB_LOG)
        print("-" * 30)

    # 检查是否存在多张指定的网卡
    found_cards = [card for card in target_network_cards if card in network_cards]
    if len(found_cards) > 1:
        # print(f"存在目标网卡: {', '.join(found_cards)}")
        write_log(f"存在目标网卡: {', '.join(found_cards)}", ADB_LOG)
    else:
        # print("未找到多张目标网卡或只有一张匹配的网卡。")
        write_log("未找到多张目标网卡或只有一张匹配的网卡。", ADB_LOG)


def route_config(commands):

    for command in commands:
        result = send_adb_command(command)
        write_log(f"{command} 命令执行结果：\r\n{result}", ADB_LOG)


# 测试主函数
def main():
    # 测试卡槽
    sim_slot = "1"
    # 测试地址
    test_url = "www.baidu.com"
    # 路由配置，根据插入的sim卡情况进行配置
    commands = [
        "ip route add default via 10.135.87.190 dev rmnet_data0",
        "iptables -t nat -A POSTROUTING -o rmnet_data0 -j MASQUERADE --random",
        "echo 'nameserver 211.138.180.5'>> /tmp/ql_lan_resolv.conf",
        "echo 'nameserver 211.138.180.4'>> /etc/resolv.conf",
    ]
    # 创建的测试 APN ID 和 APN 名称
    testapn1 = "9"
    testapn1_name = "test1"
    testapn2 = "11"
    testapn2_name = "test2"
    # 创建的datacall ID和名称
    datacall1_id = "1"
    datacall1_name = "call1"
    datacall2_id = "2"
    datacall2_name = "call2"
    # 需要检查的目标 APN ID
    target_ids = [testapn1, testapn2]
    # 需要检查的目标网卡
    target_network_cards = ["rmnet_data0", "rmnet_data1"]

    # 检查串口连接状态，确保 debug_serial 已连接
    check_port_status()
    createLogFile()  # 确保日志文件被创建
    # 打印日志路径，确认日志文件已创建
    print(f"DEBUG_LOG: {DEBUG_LOG}, ADB_LOG: {ADB_LOG}, AT_LOG: {AT_LOG}")
    # 检查串口连接状态，确保 debug_serial 已连接
    check_port_status()
    # 登录设备
    loginDevice()
    intoTestInterface_testsdk(debug_serial, DEBUG_LOG)

    # 循环测试
    while True:
        writeRuntimesToLog()

        apn_response = check_APN()
        apn_ids = extract_apn_ids(apn_response)
        check_apn_in_list(apn_ids, target_ids)
        # 设置测试APN和启动datacall
        set_apn_testsdk(testapn1, testapn1_name, sim_slot)
        set_datacall1_testsdk(datacall1_id, datacall1_name, testapn1, sim_slot)
        start_datacall_testsdk(datacall1_id)
        set_apn_testsdk(testapn2, testapn2_name, sim_slot)
        set_datacall1_testsdk(datacall2_id, datacall2_name, testapn2, sim_slot)
        start_datacall_testsdk(datacall2_id)
        # 路由配置
        route_config(commands)
        # 网卡检查
        network_info = check_network_info()
        extract_network_info(network_info, target_network_cards)
        # ping测试
        ping_testsdk(test_url)
        # 检查APN ID list
        apn_response = check_APN()
        apn_ids = extract_apn_ids(apn_response)
        check_apn_in_list(apn_ids, target_ids)
        # 删除测试datacall
        remove_datacall_testsdk(datacall1_id)
        remove_datacall_testsdk(datacall2_id)
        # 删除测试APN
        remove_APN(testapn1)
        remove_APN(testapn2)
        # 检查APN ID list
        apn_response = check_APN()
        apn_ids = extract_apn_ids(apn_response)
        check_apn_in_list(apn_ids, target_ids)


# 主程序
if __name__ == "__main__":
    main()
